#include "std_type_traits.h"

int std_type_traits() {
    // 1. 自定义编译器常量
    typedef CompileConstant<bool, true> bool_true;

    bool_true a;
    std::cout << bool(a) << std::endl;                   // return 1


    // 2. 类型判断的type_traits
    std::cout <<  std::is_const<int>::value              << std::endl;  // false   
    std::cout <<  std::is_const<const int>::value        << std::endl;  // true

    //! const int&表示表示引用不能改变其指向的值
    std::cout <<  std::is_const<const int&>::value       << std::endl;  // false

    //! 不能通过指针改变其指向的值
    std::cout <<  std::is_const<const int* >::value      << std::endl;  // false

    //! 不能改变指针变量的值, 也就是不能改变指针的指向
    std::cout <<  std::is_const<int* const>::value       << std::endl;  // true
    std::cout <<  std::is_arithmetic<int>::value         << std::endl;  // true
    std::cout <<  std::is_unsigned<int>::value           << std::endl;  // false
    std::cout <<  std::is_unsigned<unsigned int>::value  << std::endl;  // true


    //! 3. 判断两个类型的关系: 
    //   1) is_same
    //   2) is_base_of         编译期判断两个类型是否为继承关系
    //   3) is_convertible     用来判断前面的类型是否能转换为后面的类型
    std::cout <<  "==============is_same============="  << std::endl;
    std::cout <<  std::is_same<int, int>::value           << std::endl;  // true
    std::cout <<  std::is_same<int, float>::value         << std::endl;  // false
    std::cout <<  std::is_same<int, const int>::value     << std::endl;  // false
    std::cout <<  std::is_same<int, const int&>::value    << std::endl;  // false
    std::cout <<  std::is_same<int, const int*>::value    << std::endl;  // false
    std::cout <<  std::is_same<int, int&>::value          << std::endl;  // false
    std::cout <<  std::is_same<int, int*>::value          << std::endl;  // false

    // is_base_of
    std::cout <<  "==============is_base_of============="  << std::endl;
    std::cout <<  std::is_base_of<A, B>::value          << std::endl;  // true
    std::cout <<  std::is_base_of<B, A>::value          << std::endl;  // true
    std::cout <<  std::is_base_of<C, A>::value          << std::endl;  // true

    // is_base_of
    std::cout <<  "==============is_base_of============="  << std::endl;
    std::cout <<  std::is_base_of<A, B>::value          << std::endl;  // true
    std::cout <<  std::is_base_of<B, A>::value          << std::endl;  // false
    std::cout <<  std::is_base_of<C, A>::value          << std::endl;  // false

    // is_convertible
    std::cout <<  "==============is_convertible============="  << std::endl;
    std::cout <<  std::is_convertible<A, B>::value          << std::endl;  // false
    std::cout <<  std::is_convertible<B, A>::value          << std::endl;  // true
    std::cout <<  std::is_convertible<C, A>::value          << std::endl;  // false
    std::cout <<  std::is_convertible<A*, B*>::value        << std::endl;  // false
    std::cout <<  std::is_convertible<B*, A*>::value        << std::endl;  // true


    //! 4. 类型转化的type_traits
    /**
     *  1) struct add(remove)_const          移除const
     *  2) struct add(remove)_reference      移除引用
     *  3) struct add(remove)_l(r)_reference 移除/添加左(右)值引用
     *  4) struct add(remove)_pinter         移除/添加指针
    **/
    std::cout <<  "==============type convert============="  << std::endl;
    std::cout <<  std::is_same<const int, std::add_const<int>::type>::value         << std::endl;  // true
    std::cout <<  std::is_same<int&, std::add_lvalue_reference<int>::type>::value   << std::endl;  // true
    std::cout <<  std::is_same<int&&, std::add_rvalue_reference<int>::type>::value  << std::endl;  // true
    std::cout <<  std::is_same<int, std::remove_reference<int&>::type>::value       << std::endl;  // true
    std::cout <<  std::is_same<int, std::remove_reference<int&&>::type>::value      << std::endl;  // true

    // 取公共类型
    typedef std::common_type<unsigned char, short, int>::type NumType;
    //! 因为int能够同时表示三者而不丢失信息和精度
    std::cout <<  std::is_same<NumType, int>::value << std::endl;  // true


    //! 5. 条件类型
    /**
     * @brief template<bool b, class T, class F>
     *        struct conditional;
     */
    typedef std::conditional<true, int, float>::type    A;                    // int
    typedef std::conditional<std::is_integral<A>::value, long, int>::type B;  // long
    //! Notice: 可见sizeof发生在编译期间
    typedef std::conditional<(sizeof(A) > sizeof(B)), A, B>::type         C;  // B, long


    //! 6. 返回任何可调用对象的返回类型
    /**
     * @brief template<class F, class... ArgTypes>
     *        class resule_of<F(ArgTypes...)>;
     */
    typedef int(&fn_ref)(int);
    typedef int(*fn_ptr)(int);
    struct fn_class {
        int operator()(int i){
            return i;
        }
    };
    
    //! 函数不是一个可调用类型，因此需要进行转化, 先将函数转换为可调用对象
    //! 其中decltype(fn)& 与 decltype(fn)* 表示函数的引用和指针
    //! 获得引用和指针后，再调用
    typedef std::result_of<decltype(fn)&(int)>::type res_fn_v1;       // int
    typedef std::result_of<decltype(fn)*(int)>::type res_fn_v2;       // int

    typedef std::result_of<fn_ref(int)>::type        res_ref;         // int
    typedef std::result_of<fn_ptr(int)>::type        res_ptr;         // int

    //! 7. 根据条件启动或禁用类型
    // 参考头文件
    auto r1 = foo(1);                                 // ok
    auto r2 = foo(1.2);                               // ok
    // auto r3 = foo("1");                            // compile error
    auto r4 = foo2(2, 2);
    // auto r5 = foo2(2.2, 2.2);                      // compile error
    foo4(1.23);                                       // d ==> double
 
    return 0;
}